package cn.com.pc.content.service;

import cn.com.pc.content.domain.*;
import cn.com.pc.content.domain.audit.AuditStatus;
import cn.com.pc.content.domain.content.Content;
import cn.com.pc.content.domain.content.ContentRepository;
import cn.com.pc.content.domain.content.ContentType;
import cn.com.pc.content.domain.view.*;
import cn.com.pc.content.dto.*;
import cn.com.pc.content.service.es.ESQueryService;
import cn.com.pc.content.util.BeanUtils;
import cn.com.pc.content.util.ContentUtils;
import cn.com.pc.content.util.ElasticUtil;
import cn.com.pc.content.vo.ArticleViewVO;
import cn.com.pc.content.vo.CustomizedContentViewVO;
import cn.com.pc.content.vo.PostViewVO;
import cn.com.pc.content.vo.VideoViewVO;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.common.lucene.search.function.FunctionScoreQuery;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.ConstantScoreQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders;
import org.elasticsearch.script.Script;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.util.*;

@Slf4j
@Service
public class ContentListService {

    @Autowired
    private ArticleViewRepository articleViewRepository;

    @Autowired
    private VideoViewRepository videoViewRepository;

    @Autowired
    private ContentRepository contentRepository;

    @Autowired
    private PostViewRepository postViewRepository;

    @Autowired
    private ESQueryService esQueryService;

    /**
     * 召回多内容列表
     *
     * @param site
     * @param contentType
     * @param tagIds
     * @param pageForm
     * @param sort
     * @return
     */
    public Map<Long, PageResult<? extends ContentDTO>> listRecall(Site site, ContentType contentType, Set<Long> tagIds, PageForm pageForm, Sort sort) {
        Map<Long, PageResult<? extends ContentDTO>> resultMap = new HashMap<>();
        for (Long tagId : tagIds) {
            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery()
                    .mustNot(QueryBuilders.matchQuery("auditStatus", AuditStatus.Deleted.name()))
                    .must(QueryBuilders.matchQuery("tagIds", tagId));
            // 排序
            SortBuilder<?> sortBuilder = StringUtils.hasLength(sort.getSortBy()) ? SortBuilders.fieldSort(sort.getSortBy()) : SortBuilders.scoreSort();
            sortBuilder.order(sort.getSortOrder());
            // 分页
            SearchSourceBuilder searchSourceBuilder = ElasticUtil.initSearchSourceBuilder(boolQueryBuilder, sortBuilder, (pageForm.getPageNum() - 1) * pageForm.getPageSize(), pageForm.getPageSize(), 60, true);
            PageResult<? extends ContentDTO> pageResult = esQueryService.search(searchSourceBuilder, contentType.getEntityDTOClass(), pageForm.getPageNum(), pageForm.getPageSize(), ContentUtils.getIndexName(site, contentType));
            resultMap.put(tagId, pageResult);
        }
        return resultMap;
    }


    /**
     * 查询内容详情
     *
     * @param contentForm
     * @param sortRequest
     * @return
     */
    public PageResult<?> detail(Site site, Biz biz, ContentForm contentForm, Sort sortRequest, ContentType contentType, String viewType) {
        //排序
        org.springframework.data.domain.Sort sort = null;
        PageRequest pageRequest = null;
        String sortBy = sortRequest.getSortBy();
        if (StringUtils.hasLength(sortBy) && BeanUtils.isClassProperty(Content.class, sortBy)) {
            sort = org.springframework.data.domain.Sort.by(sortRequest.getDirection(), sortBy);
            pageRequest = PageRequest.of(contentForm.getPageNum() - 1,
                    contentForm.getPageSize(), sort);
        } else {
            // Content中没有的属性默认排序
            pageRequest = PageRequest.of(contentForm.getPageNum() - 1,
                    contentForm.getPageSize());
        }

        switch (contentType) {
            case Article:
                Page<ArticleViewVO> articleViewVoPage = getArticleViewVoPage(
                        site, biz, contentForm, viewType, pageRequest);
                return PageResult.fromPage(articleViewVoPage);

            case Video:
                Page<VideoViewVO> videoViewVoPage = getVideoViewVoPage(
                        site, biz, contentForm, viewType, pageRequest);
                return PageResult.fromPage(videoViewVoPage);

            case Post:
                Page<PostViewVO> postViewVoPage = getPostViewVoPage(
                        site, biz, contentForm, viewType, pageRequest);
                return PageResult.fromPage(postViewVoPage);

            case Question:
            case Audio:
            case Course:
            case ShortMessage:
                Page<CustomizedContentViewVO> customizedContentViewVoPage = getCustomizedContentViewVoPage(
                        site, biz, contentForm, viewType, pageRequest, contentType);
                return PageResult.fromPage(customizedContentViewVoPage);

//                    todo 待增加实体类
//                case AD:
//                    validError = true;
//                    break;
//                case Product:
//                    validError = true;
//                    break;
//                case Other:
//                    validError = true;
//                    break;
            default:
                return PageResult.fromPage(Page.empty());
        }
    }

    /**
     * 动态修改集合名
     *
     * @param contentType
     */
    public void setMongodbCollection(ContentType contentType) {
        contentRepository.setCollectionName("pcp_" + contentType.getName());
    }

    /**
     * 分页查询文章内容及视图
     *
     * @param site
     * @param biz
     * @param contentForm
     * @param viewType
     * @param pageRequest
     * @return
     */
    @SuppressWarnings("Duplicates")
    public Page<ArticleViewVO> getArticleViewVoPage(Site site, Biz biz, ContentForm contentForm, String viewType, PageRequest pageRequest) {
        Page<ArticleView> articlePage = null;

        if (!CollectionUtils.isEmpty(contentForm.getIds())) {
            articlePage = articleViewRepository.findAllByIdInAndAuditStatusNot(
                    contentForm.getIds(), AuditStatus.Deleted, pageRequest);

        } else if (!CollectionUtils.isEmpty(contentForm.getReferIds())) {
            articlePage = articleViewRepository.findAllByReferIdInAndSiteAndBizAndAuditStatusNot(
                    contentForm.getReferIds(), site, biz, AuditStatus.Deleted, pageRequest);

        } else {
            articlePage = Page.empty();
        }


        return articlePage.map(articleView -> {
            String view = null;
            Map<String, String> viewData = articleView.getViewData();
            if (viewData != null) {
                view = viewData.get(viewType);
            }
            return ArticleViewVO.from(articleView, viewType, view);
        });
    }

    /**
     * 分页查询视频内容及视图
     *
     * @param site
     * @param biz
     * @param contentForm
     * @param viewType
     * @param pageRequest
     * @return
     */
    @SuppressWarnings("Duplicates")
    public Page<VideoViewVO> getVideoViewVoPage(Site site, Biz biz, ContentForm contentForm, String viewType, PageRequest pageRequest) {
        Page<VideoView> videoPage = null;
        if (!CollectionUtils.isEmpty(contentForm.getIds())) {
            videoPage = videoViewRepository.findAllByIdInAndAuditStatusNot(
                    contentForm.getIds(), AuditStatus.Deleted, pageRequest);

        } else if (!CollectionUtils.isEmpty(contentForm.getReferIds())) {
            videoPage = videoViewRepository.findAllByReferIdInAndSiteAndBizAndAuditStatusNot(
                    contentForm.getReferIds(), site, biz, AuditStatus.Deleted, pageRequest);

        } else {
            videoPage = Page.empty();
        }


        return videoPage.map(videoView -> {
            String view = null;
            Map<String, String> viewData = videoView.getViewData();
            if (viewData != null) {
                view = viewData.get(viewType);
            }
            return VideoViewVO.from(videoView, viewType, view);
        });
    }

    /**
     * 分页查询定制内容及视图（帖子、问答、话题、）
     *
     * @param site
     * @param biz
     * @param contentForm
     * @param viewType
     * @param pageRequest
     * @param contentType
     * @return
     */
    @SuppressWarnings("Duplicates")
    public Page<CustomizedContentViewVO> getCustomizedContentViewVoPage(Site site, Biz biz, ContentForm contentForm, String viewType, PageRequest pageRequest, ContentType contentType) {
        Page<ContentView> contentViewPage = null;
        setMongodbCollection(contentType);
        if (!CollectionUtils.isEmpty(contentForm.getIds())) {
            contentViewPage = contentRepository.findAllByIdInAndAuditStatusNot(
                    contentForm.getIds(), AuditStatus.Deleted, pageRequest);

        } else if (!CollectionUtils.isEmpty(contentForm.getReferIds())) {
            contentViewPage = contentRepository.findAllByReferIdInAndSiteAndBizAndAuditStatusNot(
                    contentForm.getReferIds(), site, biz, AuditStatus.Deleted, pageRequest);

        } else {
            contentViewPage = Page.empty();
        }

        return contentViewPage.map(contentView -> {
            String view = null;
            Map<String, String> viewData = contentView.getViewData();
            if (viewData != null) {
                view = viewData.get(viewType);
            }
            return CustomizedContentViewVO.from(contentView, viewType, view);
        });
    }

    /**
     * 分页查询帖子内容及视图
     *
     * @param site
     * @param biz
     * @param contentForm
     * @param viewType
     * @param pageRequest
     * @return
     */
    @SuppressWarnings("Duplicates")
    public Page<PostViewVO> getPostViewVoPage(Site site, Biz biz, ContentForm contentForm, String viewType, PageRequest pageRequest) {
        Page<PostView> postViewPage = null;
        if (!CollectionUtils.isEmpty(contentForm.getIds())) {
            postViewPage = postViewRepository.findAllByIdInAndAuditStatusNot(
                    contentForm.getIds(), AuditStatus.Deleted, pageRequest);

        } else if (!CollectionUtils.isEmpty(contentForm.getReferIds())) {
            postViewPage = postViewRepository.findAllByReferIdInAndSiteAndBizAndAuditStatusNot(
                    contentForm.getReferIds(), site, biz, AuditStatus.Deleted, pageRequest);

        } else {
            postViewPage = Page.empty();
        }

        return postViewPage.map(postView -> {
            String view = null;
            Map<String, String> viewData = postView.getViewData();
            if (viewData != null) {
                view = viewData.get(viewType);
            }
            return PostViewVO.from(postView, viewType, view);
        });
    }
}
